#include <iostream>
#include <string>
#include <pthread.h>
#include <memory>
#include "../comm/httplib.h"
#include "oj_control.hpp"
#include "session.hpp"
#include "user_manage.hpp"

using namespace httplib;
using namespace ns_control;
using namespace ns_session;
using namespace ns_user_manage;

void *check(void *arg)
{
    sleep(1);
    pthread_detach(pthread_self());
    Control *ctrl = (Control *)arg;
    LoadBlance *loadblance = &ctrl->_lb;

    while (1)
    {
        std::vector<Machine> machines = loadblance->_machines;
        for (auto &machine : machines)
        {
            if (machine.status == OFFLINE)
            {
                Client clt(machine.ip, machine.port);
                if (auto res = clt.Post("/check_net", "check", "text/plain;charset=utf-8"))
                {
                    // 得到响应，证明对端主机上线
                    loadblance->Online(machine.id);
                }
            }
        }
    }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage:\n\t" << argv[0] << " port" << std::endl;
        return -1;
    }
    // 控制器
    Control ctrl;
    pthread_t tid;
    pthread_create(&tid, nullptr, check, &ctrl);
    // 会话
    std::shared_ptr<AllSessionInfo> all_sess(new AllSessionInfo);
    std::shared_ptr<Server> svr(new Server);
    std::shared_ptr<UserManage> manager(new UserManage);

    svr->Get(R"(/all_questions)", [&ctrl](const Request &req, Response &rep)
             {
                //LOG(INFO, "get questions request");
                std::string html;
                ctrl.GetAllQuestionsListHtml(html);
                rep.set_content(html, "text/html;charset=utf-8"); });
    svr->Get(R"(/question/(\d+))", [&ctrl](const Request &req, Response &rep)
             { 
                //LOG(INFO, "get one question request");
                std::string number = req.matches[1];
                std::string html;
                ctrl.GetOneQuestionByNumberHtml(number, html);
                rep.set_content(html, "text/html;charset=utf-8"); });
    svr->Post(R"(/judge/(\d+))", [&ctrl](const Request &req, Response &rep)
              { 
                //LOG(INFO, "get one judge request");
                std::string number = req.matches[1];
                std::string out_json;
                ctrl.Judge(number, req.body, out_json); 
                rep.set_content(out_json, "application/json;charset=utf-8"); });
    // 注册
    /******
     * json
     * user 账户名
     * password 密码
     * ******/
    svr->Post("/register", [&ctrl](const Request &req, Response &rep)
              {
                LOG(INFO, "get a register request");
                std::string out_json;
                ctrl.Register(req.body, out_json);
                rep.set_content(out_json, "application/json;charset=utf-8"); });
    // 登录
    svr->Post("/sign", [&ctrl, &all_sess, &manager](const Request &req, Response &rep)
              {
                LOG(INFO, "get a sign request");
                std::string out_json;
                int user_id = ctrl.SignIn(req.body, "user", out_json);
                std::string tmp;
                if (user_id > 0)
                {
                    Session sess(req.body, user_id, "user");
                    std::string session_id = sess.GetSessionId();
                    tmp = "JSESSION=" + session_id;
                    all_sess->SetSessionInfo(session_id, sess);
                    // 将用户添加到管理
                    manager->AddUserToSet(user_id, 1);
                }

                rep.set_header("Set-Cookie", tmp.c_str());// 返回cookie
                rep.set_content(out_json, "application/json;charset=utf-8"); });
    svr->Get("/GetUserId", [&all_sess](const Request &req, Response &rep)
             {
                    //1.会话校验
                    Json::Value resp_json;
                    resp_json["id"] = all_sess->CheckSessionInfo(req);

                    std::string out_json;
                    Json::FastWriter writer;
                    out_json = writer.write(resp_json); 
                    rep.set_content(out_json, "application/json;charset=utf-8"); });
    svr->Post("/GetUserName", [&all_sess, &ctrl](const Request &req, Response &rep)
              {
                    LOG(INFO, "get a get username request");
                    Json::Value in_json;
                    Json::Reader reader;
                    reader.parse(req.body, in_json);
                    std::string out_json;
                    int id = in_json["id"].asInt();
                    std::string strId = in_json["strId"].asString();
                    std::string table = in_json["table"].asString();
           
                    Json::Value out_value;
                    out_value["username"] = ctrl.GetUserName(id, strId, table);
                    Json::FastWriter writer;
                    out_json = writer.write(out_value); 
                    rep.set_content(out_json, "application/json;charset=utf-8"); });
    // 修改密码
    svr->Post("/forget", [&ctrl](const Request &req, Response &rep)
              {
                LOG(INFO, "get a forget password request");
                std::string out_json;
                ctrl.Forget(req.body, out_json);
                rep.set_content(out_json, "application/json;charset=utf-8"); });
    // 管理员登录
    svr->Post("/administrator", [&ctrl, &all_sess, &manager](const Request &req, Response &rep)
              {
                LOG(INFO, "get a administrator sign request");
                std::string out_json;
                int administrator_id = ctrl.SignIn(req.body, "administrators", out_json);
                std::string tmp;
                if (administrator_id > 0)
                {
                    Session sess(req.body, administrator_id, "administrator");
                    std::string session_id = sess.GetSessionId();
                    tmp = "JSESSION=" + session_id;
                    all_sess->SetSessionInfo(session_id, sess);
                    // 将用户添加到管理
                    manager->AddUserToSet(administrator_id);
                }
                rep.set_header("Set-Cookie", tmp.c_str());// 返回cookie
                rep.set_content(out_json, "application/json;charset=utf-8"); });
    svr->Post("/add_question", [&ctrl](const Request &req, Response &rep)
              {
                LOG(INFO, "get a add question request");
                std::string out_json;
                ctrl.AddQuestion(req.body, out_json);
                rep.set_content(out_json, "application/json;charset=utf-8"); });
    svr->set_base_dir("wwwroot");
    svr->listen("0.0.0.0", atoi(argv[1]));

    return 0;
}
